import Axios, { AxiosResponse } from "axios";
import qs from "qs";

import router from '@/router';

import pinia from "@store/pinia";
import useUserStore from "@store/modules/user";
const userStore = useUserStore(pinia);

import config from "@/config";
import {refreshToken} from "@/request/apis/login";
const { baseUrl } = config;
import { generateUUID } from "@/utils"

// 传参类型
export const CONTENT_TYPE = "Content-Type";

export const FORM_URLENCODED = "application/x-www-form-urlencoded; charset=UTF-8";

export const APPLICATION_JSON = "application/json; charset=UTF-8";

let isRefreshToken = false; //是否正在刷新token
let requestList = <any>[]; //请求队列


const service = Axios.create({
  // baseURL: window.configObj.baseUrl,
  baseURL: baseUrl,
  timeout: 5 * 1000,
});

// 请求拦截
service.interceptors.request.use((config) => {
    // 请求参数形式-默认json格式，传了就是传入的格式
    config.headers[CONTENT_TYPE] = config.headers[CONTENT_TYPE]
      ? config.headers[CONTENT_TYPE]
      : APPLICATION_JSON;

    // 携带token
    config.headers["token"] =
        userStore.token && location.hash !== "login" ? userStore.token : "";

    // formdata形式 参数序列化 "name=aa&age=18" qs.parse()  -> {name: 'aa', age: '18'}
    config.data =
      config.headers[CONTENT_TYPE] === FORM_URLENCODED
        ? qs.stringify(config.data)
        : config.data;


    //暂存请求
    const requestKey = generateUUID();
    config.cancelToken = new Axios.CancelToken(cancel => {
      userStore.pushCancel(requestKey, cancel)
    })
    config.requestKey = requestKey
    return config;
  },
  (error) => {
    return Promise.reject(error.response);
  }
);

// 响应拦截
service.interceptors.response.use(
  async (response) => {
    const requestKey = response.config.requestKey
    userStore.removeCancel(requestKey)
    if (response.status === 200) {

      /*处理二进制数据直接返回 */
      const contentType = response.headers['content-type'];
      const isBlobData = /^(application\/octet-stream|application\/pdf|image\/|audio\/|video\/)/.test(contentType);    
      // 二进制数据直接返回
      if (isBlobData || ['blob', 'arraybuffer'].includes(response.config.responseType as string)) {
        return response.data;
      }
      /*处理二进制数据直接返回 end*/

      const data = response.data;
      if(data.code === 0){ //业务code为0成功
        return data.data;
      }else{
        if(data.code === 401){//认证失败的处理
          //先判断是否正在刷新token，是则将请求放到队列里，否去调刷新接口，成功则更新token等，把队列中的内容重新发送
          if(!isRefreshToken){
            isRefreshToken = true;
            try{
              let res = await refreshToken({refreshToken:userStore.refreshToken});
              userStore.saveToken(res.accessToken,res.refreshToken);
              requestList.forEach((item:any)=>{
                item();
              });
              requestList=[];
              isRefreshToken=false;
              let currResonse = await service(response.config);
              return currResonse;
            }catch(refreshError) {
              isRefreshToken=false;
              userStore.removeUserInfo();
              router.replace({ name: "login"});
            }
          } else {
            return new Promise((resolve)=>{
              requestList.push(()=>{
                resolve(service(response.config));
              });
            });
          }
        }
        ElMessage.error("操作失败！" + data.message);
        return Promise.reject(new Error(data.message));
      }

    } else {
      ElMessage.error("响应异常:" + response.status.toString());
    }
  },
  (error) => {
    if (process.env.NODE_ENV === "development") {
      console.log("报错信息：", error.response);
    }
    if (
      error.code === "ECONNABORTED" &&
      error.message.indexOf("timeout") !== -1
    ) {
      ElMessage.error("请求超时");
      return;
    }
    ElMessage.error("请求异常:" + error);
    return Promise.reject(error);
  }
);

export default service;
